Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ jobs:
- name: Test framework registry
run: yarn test:frameworks

# The URL builder behind the shared ApiLink component.
- name: Test ApiLink URLs
run: yarn test:api-link

# One list of products: docs-schema.yml, products.json, features.json,
# skills.json, URL_PRODUCT_MAPPING and page frontmatter must all agree
# with content/registry/products.yml.
Expand Down
19 changes: 1 addition & 18 deletions docs/partials/_ai-powered-barcode-scanning.mdx
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
'web': 'web',
'react-native': 'react-native',
'flutter': 'flutter',
'capacitor': 'capacitor',
'cordova': 'cordova',
'kmp': 'kmp',
'net-ios': 'dotnet.ios',
'net-android': 'dotnet.android',
};
import ApiLink from '@site/src/components/ApiLink';

export const upperCase = {
scanIntention: 'scanIntention',
Expand Down Expand Up @@ -71,10 +58,6 @@ export const symbolTokens = {

export const Only = ({when, children}) => (when ? <>{children}</> : null);

export const ApiLink = ({framework, page, anchor, children}) => (
<Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[framework]}/${page}#${anchor}`}><code>{children}</code></Link>
);

export const sparkScanSettings = 'barcode-capture/api/spark-scan-settings.html';
export const barcodeCaptureSettings = 'barcode-capture/api/barcode-capture-settings.html';
export const sparkScanProperty = 'property-scandit.datacapture.barcode.spark.SparkScanSettings.';
Expand Down
15 changes: 1 addition & 14 deletions docs/partials/advanced/_id-side-capture-callbacks.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
'web': 'web',
'react-native': 'react-native',
'capacitor': 'capacitor',
'cordova': 'cordova',
};
import ApiLink from '@site/src/components/ApiLink';

export const hybridFrameworks = ['react-native', 'capacitor', 'cordova'];

Expand Down Expand Up @@ -46,10 +37,6 @@ export const symbolTokens = {

export const Only = ({when, children}) => (when ? <>{children}</> : null);

export const ApiLink = ({framework, page, anchor, children}) => (
<Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[framework]}/${page}#${anchor}`}><code>{children}</code></Link>
);

export const settingsPage = 'id-capture/api/id-capture-settings.html';
export const settingsProperty = 'property-scandit.datacapture.id.IdCaptureSettings.';
export const capturedIdPage = 'id-capture/api/captured-id.html';
Expand Down
11 changes: 1 addition & 10 deletions docs/partials/advanced/_id-visa-mrz-fields.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
'web': 'web',
};
import ApiLink from '@site/src/components/ApiLink';

export const symbolTokens = {
'ios': {
Expand Down Expand Up @@ -41,10 +36,6 @@ export const symbolTokens = {

export const Only = ({when, children}) => (when ? <>{children}</> : null);

export const ApiLink = ({framework, page, anchor, children}) => (
<Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[framework]}/${page}#${anchor}`}><code>{children}</code></Link>
);

export const capturedIdPage = 'id-capture/api/captured-id.html';
export const capturedIdProperty = 'property-scandit.datacapture.id.CapturedId.';
export const mrzPage = 'id-capture/api/mrz-result.html';
Expand Down
11 changes: 1 addition & 10 deletions docs/partials/advanced/_shipping-label-scanning.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
'web': 'web',
};
import ApiLink from '@site/src/components/ApiLink';

export const symbolTokens = {
'ios': {
Expand Down Expand Up @@ -104,10 +99,6 @@ export const carrierValues = {

export const Only = ({when, children}) => (when ? <>{children}</> : null);

export const ApiLink = ({framework, page, anchor, children}) => (
<Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[framework]}/${page}#${anchor}`}><code>{children}</code></Link>
);

export const DocLink = ({framework, page, children}) => (
<Link to={`/sdks/${framework}/label-capture/${page}`}>{children}</Link>
);
Expand Down
11 changes: 1 addition & 10 deletions docs/partials/count/_clustering-automatic-method.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
};
import ApiLink from '@site/src/components/ApiLink';

export const symbolTokens = {
'ios': {
Expand All @@ -30,10 +25,6 @@ export const symbolTokens = {

export const Only = ({when, children}) => (when ? <>{children}</> : null);

export const ApiLink = ({framework, page, anchor, children}) => (
<Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[framework]}/${page}#${anchor}`}><code>{children}</code></Link>
);

export const settingsPage = 'barcode-capture/api/barcode-count-settings.html';
export const settingsProperty = 'property-scandit.datacapture.barcode.count.BarcodeCountSettings.';
export const methodPage = 'core/api/automatic-clustering-method.html';
Expand Down
14 changes: 2 additions & 12 deletions docs/partials/intro/_about-matrixscan-pick.mdx
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import Link from '@docusaurus/Link';

export const apiTokens = {
'ios': 'ios',
'android': 'android',
'capacitor': 'capacitor',
'cordova': 'cordova',
'flutter': 'flutter',
'react-native': 'react-native',
'net/ios': 'dotnet.ios',
'net/android': 'dotnet.android',
};
import ApiLink from '@site/src/components/ApiLink';

MatrixScan Pick is a pre-built UI that uses augmented reality overlays to highlight specific items that need to be picked. Whereas MatrixScan AR is fully customizable, MatrixScan Pick is a pre-built solution that allows you to add a scan and pick experience with augmented reality to an existing native app, with just a few lines of code.

MatrixScan Pick is implemented through functionality provided by <Link to={`https://docs.scandit.com/data-capture-sdk/${apiTokens[props.framework]}/barcode-capture/api/barcode-pick.html`}><code>BarcodePick</code></Link>.
MatrixScan Pick is implemented through functionality provided by <ApiLink framework={props.framework} page="barcode-capture/api/barcode-pick.html">BarcodePick</ApiLink>.

## UI Overview

Expand Down
29 changes: 29 additions & 0 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,32 @@ function buildApiReferencePrefixByMajor(): Record<string, string> {
return out;
}

/**
* The path prefix of the API reference each docs version links to, keyed by
* version name: `{ current: "", "8.6.1": "/8.6", "7.6.15": "/7.6", "6.28.11": "/6.28" }`.
* Consumed by src/components/ApiLink, which builds API-reference URLs in code.
*
* Decided by the version's role, not by scanning its text: the current version
* links the unversioned tree, and a frozen version links its own
* <major>.<minor> line. That is the rule scripts/update-version.py applies to a
* snapshot's text at the freeze (API_REFERENCE_LINK_REWRITES), and it has to be
* restated here because ApiLink's URLs are not in the text the script rewrites.
* A text scan (`linksToOwnApiLine`) would be wrong for ApiLink twice over: it
* finds less as partials move to ApiLink, and one deliberately versioned link
* in docs/ would switch every ApiLink on the current version.
*/
function buildApiReferencePrefixByVersion(): Record<string, string> {
const out: Record<string, string> = { current: "" };
for (const name of frozenVersionNames()) {
const match = /^(\d+\.\d+)\.\d+/.exec(name);
// update-version.py raises on the same input; failing here keeps a
// misnamed snapshot from silently linking the current API reference.
if (!match) throw new Error(`Cannot derive an API-reference line from docs version "${name}".`);
out[name] = `/${match[1]}`;
}
return out;
}

/**
* Map a major version typed in a query ("v7", "sdk 6") to the tag of the version
* a reader on that line is actually served.
Expand Down Expand Up @@ -981,6 +1007,9 @@ const config: Config = {
// Major -> prefix of the API reference that major's docs link to. Used by
// the 404 page to recover versioned API-reference links.
apiReferencePrefixByMajor: buildApiReferencePrefixByMajor(),
// Docs version name -> prefix of the API reference that version links to.
// Used by src/components/ApiLink.
apiReferencePrefixByVersion: buildApiReferencePrefixByVersion(),
versionNumberByTag: buildVersionNumberByTag(docsVersions),
},

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"verify:frameworks": "node scripts/verify-frameworks.cjs",
"verify:agents-md": "node scripts/verify-agents-md.cjs",
"test:frameworks": "node scripts/test-frameworks.cjs",
"test:api-link": "node scripts/test-api-link.cjs",
"verify:registry": "node scripts/verify-registry.cjs",
"test:registry": "node scripts/test-registry.cjs",
"test:not-found": "node scripts/test-not-found.cjs",
Expand Down
9 changes: 5 additions & 4 deletions scripts/fixtures/verify-frameworks-fixture.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type FrameworkDef = {
display: string;
routeSegment: string | null;
agentSkills: boolean;
apiReferenceSegment: string | null;
};

export const FRAMEWORKS: FrameworkDef[] = [
Expand All @@ -53,7 +54,7 @@ ${entries
(e) =>
` { slug: "${e.slug}", display: "${e.display}", routeSegment: ` +
`${e.routeSegment === null ? "null" : `"${e.routeSegment}"`}, ` +
`agentSkills: ${e.agentSkills} },`,
`agentSkills: ${e.agentSkills}, apiReferenceSegment: "${e.slug}" },`,
)
.join("\n")}
];
Expand Down Expand Up @@ -174,7 +175,7 @@ Body.
// entryPairs reported it.
if (mutate === "registry-spread-inside-entry") {
registry = registry.replace(
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: false },`,
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: false, apiReferenceSegment: "hosted" },`,
` { slug: "hosted", display: "Hosted", routeSegment: null, ...HOSTED_EXTRAS },`,
);
}
Expand All @@ -194,8 +195,8 @@ Body.
if (mutate === "registry-nested-routesegment") {
registry = registry
.replace(
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: false },`,
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: true, meta: { routeSegment: "id-bolt" } },`,
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: false, apiReferenceSegment: "hosted" },`,
` { slug: "hosted", display: "Hosted", routeSegment: null, agentSkills: true, apiReferenceSegment: "hosted", meta: { routeSegment: "id-bolt" } },`,
);
}
if (mutate === "registry-missing-union-member") {
Expand Down
142 changes: 142 additions & 0 deletions scripts/test-api-link.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#!/usr/bin/env node
"use strict";
/**
* Tests for the shared ApiLink component's URL builder
* (src/components/ApiLink/apiReferenceUrl.ts) and the registry field it reads.
*
* Which API-reference tree a docs version links to is not decided here: it
* comes from the `apiReferencePrefixByVersion` custom field, which
* buildApiReferencePrefixByVersion in docusaurus.config.ts sets by the
* version's role (current, or frozen on its own line). These tests cover what
* the component adds on top of that prefix.
*/
const fs = require("fs");
const path = require("path");
const assert = require("assert");
const ts = require("typescript");

const ROOT = path.join(__dirname, "..");

const cache = new Map();
function loadTs(relPath) {
if (cache.has(relPath)) return cache.get(relPath);
const full = path.join(ROOT, relPath);
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019 },
}).outputText;
const exports = {};
const localRequire = (id) =>
id.startsWith("@site/") ? loadTs(id.replace("@site/", "") + ".ts") : require(id);
cache.set(relPath, exports);
new Function("exports", "require", "module", "__filename", js)(
exports, localRequire, { exports }, full,
);
return exports;
}

const { apiReferenceUrl } = loadTs("src/components/ApiLink/apiReferenceUrl.ts");
const { FRAMEWORKS } = loadTs("src/constants/frameworks.ts");

let failures = 0;
function test(name, fn) {
try {
fn();
console.log(` ok ${name}`);
} catch (err) {
failures++;
console.log(` FAIL ${name}\n ${err.message}`);
}
}

console.log("ApiLink URL builder");

test("an empty prefix links the unversioned API reference", () => {
assert.strictEqual(
apiReferenceUrl("ios", "core/api/camera.html", "class-scandit.datacapture.core.Camera", ""),
"https://docs.scandit.com/data-capture-sdk/ios/core/api/camera.html#class-scandit.datacapture.core.Camera",
);
});

test("a version prefix links that line's API reference", () => {
assert.strictEqual(
apiReferenceUrl("android", "core/api/camera.html", "x", "/7.6"),
"https://docs.scandit.com/7.6/data-capture-sdk/android/core/api/camera.html#x",
);
});

test(".NET frameworks link their dotnet.* segments", () => {
assert.strictEqual(
apiReferenceUrl("net-ios", "a.html", undefined, ""),
"https://docs.scandit.com/data-capture-sdk/dotnet.ios/a.html",
);
assert.strictEqual(
apiReferenceUrl("net-android", "a.html", undefined, ""),
"https://docs.scandit.com/data-capture-sdk/dotnet.android/a.html",
);
});

test("no anchor means no '#', and a leading slash on the page is dropped", () => {
assert.strictEqual(
apiReferenceUrl("web", "/core/api/camera.html", undefined, ""),
"https://docs.scandit.com/data-capture-sdk/web/core/api/camera.html",
);
});

test("a framework without an API reference gets no URL", () => {
for (const fw of ["linux", "titanium", "hosted"]) {
assert.strictEqual(apiReferenceUrl(fw, "a.html", "b", ""), null, fw);
}
});

test("a route segment or an alias resolves like its slug", () => {
const expected = apiReferenceUrl("net-ios", "a.html", undefined, "");
assert.strictEqual(apiReferenceUrl("net/ios", "a.html", undefined, ""), expected);
assert.strictEqual(apiReferenceUrl("netios", "a.html", undefined, ""), expected);
});

test("an unknown framework throws instead of dropping the link", () => {
assert.throws(() => apiReferenceUrl("netios-typo", "a.html", undefined, ""), /unknown framework/);
});

test("every registry entry states its API-reference segment", () => {
for (const f of FRAMEWORKS) {
assert.ok(f.apiReferenceSegment !== undefined, `${f.slug} has no apiReferenceSegment`);
}
});

test("the search bar's .NET mapping agrees with the registry", () => {
// src/theme/SearchBar keeps its own route-segment <-> API-segment map.
const searchBar = fs.readFileSync(path.join(ROOT, "src/theme/SearchBar/index.js"), "utf8");
for (const f of FRAMEWORKS) {
if (!f.routeSegment || !f.apiReferenceSegment || f.routeSegment === f.apiReferenceSegment) continue;
assert.ok(
searchBar.includes(`"${f.routeSegment}": "${f.apiReferenceSegment}"`),
`SearchBar has no "${f.routeSegment}": "${f.apiReferenceSegment}" entry`,
);
}
});

test("no doc builds its own API-reference link from a framework map", () => {
// An inline ApiLink, a per-partial framework map, or an expression after
// /data-capture-sdk/ in a template literal or a string concatenation.
const OWN_BUILDER =
/export const ApiLink\b|\bapiTokens\b|data-capture-sdk\/\$\{|data-capture-sdk\/['"`]\s*\+/;
const offenders = [];
const walk = (dir) => {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const p = path.join(dir, entry.name);
if (entry.isDirectory()) walk(p);
else if (/\.mdx?$/.test(entry.name) && OWN_BUILDER.test(fs.readFileSync(p, "utf8"))) {
offenders.push(path.relative(ROOT, p));
}
}
};
walk(path.join(ROOT, "docs"));
assert.deepStrictEqual(offenders, [], "import @site/src/components/ApiLink instead");
});

if (failures) {
console.log(`\n${failures} failing`);
process.exit(1);
}
console.log("\nall passing");
Loading
Loading