dsh-standards 1.0.2 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/40-checker/README.md +0 -0
- package/40-checker/bin/dsh-plugin-verify.mjs +0 -0
- package/40-checker/fixtures/bad/index.mjs +0 -0
- package/40-checker/fixtures/bad/package.json +0 -0
- package/40-checker/fixtures/bad-manifest/index.js +0 -0
- package/40-checker/fixtures/bad-manifest/package.json +0 -0
- package/40-checker/fixtures/bundle/cordis.patch.yml +0 -0
- package/40-checker/fixtures/bundle/package.json +0 -0
- package/40-checker/fixtures/bundle/server.mjs +0 -0
- package/40-checker/fixtures/bundle-patch-only/cordis.patch.yml +3 -0
- package/40-checker/fixtures/bundle-patch-only/package.json +12 -0
- package/40-checker/fixtures/bundle-v0/cordis.patch.yml +0 -0
- package/40-checker/fixtures/bundle-v0/package.json +0 -0
- package/40-checker/fixtures/bundle-v0/server.mjs +0 -0
- package/40-checker/fixtures/c12-command-arg/index.mjs +7 -0
- package/40-checker/fixtures/c12-command-arg/package.json +10 -0
- package/40-checker/fixtures/c12-comment/index.mjs +3 -0
- package/40-checker/fixtures/c12-comment/package.json +10 -0
- package/40-checker/fixtures/c12-compare/index.mjs +3 -0
- package/40-checker/fixtures/c12-compare/package.json +10 -0
- package/40-checker/fixtures/c12-doc-string/index.mjs +13 -0
- package/40-checker/fixtures/c12-doc-string/package.json +10 -0
- package/40-checker/fixtures/c12-grant/index.mjs +3 -0
- package/40-checker/fixtures/c12-grant/package.json +10 -0
- package/40-checker/fixtures/c12-string/index.mjs +3 -0
- package/40-checker/fixtures/c12-string/package.json +10 -0
- package/40-checker/fixtures/client-missing/client.js +0 -0
- package/40-checker/fixtures/client-missing/index.js +0 -0
- package/40-checker/fixtures/client-missing/package.json +0 -0
- package/40-checker/fixtures/declaration-file/index.d.ts +1 -0
- package/40-checker/fixtures/declaration-file/index.mjs +9 -0
- package/40-checker/fixtures/declaration-file/package.json +10 -0
- package/40-checker/fixtures/flow-config/index.js +0 -0
- package/40-checker/fixtures/flow-config/package.json +0 -0
- package/40-checker/fixtures/fs-write/index.mjs +0 -0
- package/40-checker/fixtures/fs-write/package.json +0 -0
- package/40-checker/fixtures/good/index.mjs +0 -0
- package/40-checker/fixtures/good/package.json +0 -0
- package/40-checker/fixtures/hang/index.mjs +0 -0
- package/40-checker/fixtures/hang/package.json +0 -0
- package/40-checker/fixtures/import-local-side-effect/index.mjs +11 -0
- package/40-checker/fixtures/import-local-side-effect/package.json +21 -0
- package/40-checker/fixtures/import-local-side-effect/side-effectful.mjs +5 -0
- package/40-checker/fixtures/import-open-readonly/index.mjs +14 -0
- package/40-checker/fixtures/import-open-readonly/package.json +19 -0
- package/40-checker/fixtures/import-package-only/index.mjs +11 -0
- package/40-checker/fixtures/import-package-only/package.json +21 -0
- package/40-checker/fixtures/import-parse-error/index.mjs +5 -0
- package/40-checker/fixtures/import-parse-error/package.json +10 -0
- package/40-checker/fixtures/import-side-effect/index.mjs +14 -0
- package/40-checker/fixtures/import-side-effect/package.json +19 -0
- package/40-checker/fixtures/import-side-effect-nonentry/index.mjs +9 -0
- package/40-checker/fixtures/import-side-effect-nonentry/package.json +19 -0
- package/40-checker/fixtures/import-side-effect-nonentry/selfcheck.mjs +8 -0
- package/40-checker/fixtures/import-void-main/index.mjs +16 -0
- package/40-checker/fixtures/import-void-main/package.json +19 -0
- package/40-checker/fixtures/known-answer/expected.json +0 -0
- package/40-checker/fixtures/market-index-real.json +0 -0
- package/40-checker/fixtures/market-index.json +0 -0
- package/40-checker/fixtures/negative/bad-entry/package.json +0 -0
- package/40-checker/fixtures/negative/no-entry/package.json +0 -0
- package/40-checker/fixtures/negative/no-patch/package.json +0 -0
- package/40-checker/fixtures/negative/root-missing/cordis.patch.yml +0 -0
- package/40-checker/fixtures/negative/root-missing/package.json +0 -0
- package/40-checker/fixtures/negative/workspace/package.json +0 -0
- package/40-checker/fixtures/no-source/package.json +19 -0
- package/40-checker/fixtures/parse-error-nonentry/index.mjs +2 -0
- package/40-checker/fixtures/parse-error-nonentry/package.json +10 -0
- package/40-checker/fixtures/parse-error-nonentry/references/broken.js +1 -0
- package/40-checker/package.json +0 -0
- package/40-checker/samples/README.md +0 -0
- package/40-checker/samples/entry18.json +0 -0
- package/40-checker/samples/frame.json +0 -0
- package/40-checker/scripts/apply-overlay.mjs +0 -0
- package/40-checker/scripts/attestation-check.mjs +0 -0
- package/40-checker/scripts/bundle-smoke.mjs +0 -0
- package/40-checker/scripts/claim-check.mjs +0 -0
- package/40-checker/scripts/clause-map.mjs +0 -0
- package/40-checker/scripts/collect-fixtures.mjs +0 -0
- package/40-checker/scripts/dashboard.mjs +0 -0
- package/40-checker/scripts/dco-check.mjs +0 -0
- package/40-checker/scripts/dependabot-check.mjs +0 -0
- package/40-checker/scripts/doc-commands-check.mjs +0 -0
- package/40-checker/scripts/entry-scan.mjs +0 -0
- package/40-checker/scripts/entry-validate.mjs +0 -0
- package/40-checker/scripts/entry18-attribution.mjs +0 -0
- package/40-checker/scripts/entry18-ci.mjs +0 -0
- package/40-checker/scripts/entry18-realweb-summary.mjs +0 -0
- package/40-checker/scripts/entry18-web.mjs +0 -0
- package/40-checker/scripts/evidence-chain.mjs +0 -0
- package/40-checker/scripts/flow-index.mjs +0 -0
- package/40-checker/scripts/flow-sample-ci.mjs +0 -0
- package/40-checker/scripts/governance-check.mjs +0 -0
- package/40-checker/scripts/host-farm.mjs +0 -0
- package/40-checker/scripts/journey-config-observe.mjs +0 -0
- package/40-checker/scripts/journey-disclosure-shape.mjs +0 -0
- package/40-checker/scripts/journey-runtime.mjs +0 -0
- package/40-checker/scripts/journey.mjs +0 -0
- package/40-checker/scripts/label-drift.mjs +0 -0
- package/40-checker/scripts/label-sync.mjs +0 -0
- package/40-checker/scripts/label-verify.mjs +0 -0
- package/40-checker/scripts/landlock-exec.c +0 -0
- package/40-checker/scripts/level-audit.mjs +0 -0
- package/40-checker/scripts/m1-sidecar.mjs +0 -0
- package/40-checker/scripts/m2-runner.mjs +0 -0
- package/40-checker/scripts/round-robin.mjs +0 -0
- package/40-checker/scripts/runtime-child.mjs +0 -0
- package/40-checker/scripts/sample-frame.mjs +0 -0
- package/40-checker/scripts/sample20-ci.mjs +0 -0
- package/40-checker/scripts/sample60-ci.mjs +0 -0
- package/40-checker/scripts/stale-check.mjs +0 -0
- package/40-checker/scripts/surveillance.mjs +0 -0
- package/40-checker/scripts/web-probe.mjs +0 -0
- package/40-checker/src/cli.mjs +1 -1
- package/40-checker/src/client-shape.mjs +0 -0
- package/40-checker/src/declarations.mjs +514 -19
- package/40-checker/src/index.mjs +0 -0
- package/40-checker/src/install-spec.mjs +0 -0
- package/40-checker/src/label.mjs +0 -0
- package/40-checker/src/manifest.mjs +5 -0
- package/40-checker/src/permissions.mjs +0 -0
- package/40-checker/src/report.mjs +0 -0
- package/40-checker/src/result.mjs +0 -0
- package/40-checker/src/runtime.mjs +0 -0
- package/40-checker/src/semver.mjs +0 -0
- package/40-checker/src/util.mjs +0 -0
- package/40-checker/test/attestation.test.mjs +0 -0
- package/40-checker/test/checks.test.mjs +243 -1
- package/40-checker/test/claim.test.mjs +0 -0
- package/40-checker/test/client-shape.test.mjs +0 -0
- package/40-checker/test/dco.test.mjs +0 -0
- package/40-checker/test/entry-validate.test.mjs +0 -0
- package/40-checker/test/governance.test.mjs +0 -0
- package/40-checker/test/label.test.mjs +0 -0
- package/40-checker/test/level-audit.test.mjs +0 -0
- package/40-checker/test/levels.test.mjs +0 -0
- package/40-checker/test/ops.test.mjs +0 -0
- package/40-checker/test/permissions.test.mjs +0 -0
- package/40-checker/test/semver.test.mjs +0 -0
- package/40-checker/test/verify.test.mjs +0 -0
- package/40-checker/vendor/babel/README.md +10 -0
- package/40-checker/vendor/babel/index.cjs +3 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-string-parser/LICENSE +22 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-string-parser/README.md +19 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-string-parser/lib/index.d.ts +41 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-string-parser/lib/index.js +286 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-string-parser/package.json +31 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/LICENSE +22 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/README.md +19 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/lib/identifier-browser.js +62 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/lib/identifier.js +60 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/lib/index.d.ts +28 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/lib/index.js +27 -0
- package/40-checker/vendor/babel/node_modules/@babel/helper-validator-identifier/package.json +45 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/CHANGELOG.md +1073 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/LICENSE +19 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/README.md +19 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/bin/babel-parser.js +14 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/lib/index.d.ts +1047 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/lib/index.js +14612 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/package.json +57 -0
- package/40-checker/vendor/babel/node_modules/@babel/parser/typings/babel-parser.d.ts +636 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/LICENSE +22 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/README.md +19 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/lib/index-legacy.d.ts +2765 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/lib/index.d.ts +3668 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/lib/index.js +10758 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/lib/index.js.flow +2618 -0
- package/40-checker/vendor/babel/node_modules/@babel/types/package.json +38 -0
- package/CHANGELOG.md +50 -0
- package/LICENSE +0 -0
- package/LICENSE-APACHE +0 -0
- package/LICENSE-CC-BY +0 -0
- package/NOTICE +0 -0
- package/NOTICE.md +0 -0
- package/README.md +0 -0
- package/bin/dsh-levels.mjs +0 -0
- package/bin/dsh-standards.mjs +0 -0
- package/docs/BOOST-FIXTURES-2026-11-02.md +0 -0
- package/docs/DEVELOPER-JOURNEY.md +0 -0
- package/docs/HOST-J3-BUG-REPORT-DRAFT.md +0 -0
- package/docs/HOST-J3-CONFIG-REPRO-2026-11-02.md +0 -0
- package/docs/NAMING-FALLBACK.md +0 -0
- package/docs/fork-policy.md +0 -0
- package/docs/full-test-plan-2026-11-02.md +0 -0
- package/docs/incident.md +0 -0
- package/docs/onboarding.md +0 -0
- package/docs/privacy.md +0 -0
- package/docs/release.md +0 -0
- package/docs/scope-security.md +0 -0
- package/docs/status-taxonomy.md +0 -0
- package/docs/sunset.md +0 -0
- package/docs/translating.md +0 -0
- package/package.json +2 -1
- package/spec/README.md +0 -0
- package/spec/boost/README.md +0 -0
- package/spec/clauses.json +0 -0
- package/spec/entry/README.md +0 -0
- package/spec/flow/README.md +0 -0
- package/spec/levels.json +0 -0
- package/spec/levels.schema.json +0 -0
- package/spec/reference-suite.json +0 -0
- package/spec/schemas/attestation.schema.json +0 -0
- package/spec/schemas/evidence.schema.json +0 -0
- package/spec/schemas/report.schema.json +0 -0
|
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { runManifestChecks } from '../src/manifest.mjs'
|
|
6
|
-
import { checkCapabilities, checkCredentials, checkLabels } from '../src/declarations.mjs'
|
|
6
|
+
import { checkCapabilities, checkCredentials, checkImportTimeAdvisory, checkLabels } from '../src/declarations.mjs'
|
|
7
7
|
import { readSources } from '../src/util.mjs'
|
|
8
8
|
import { buildReport } from '../src/report.mjs'
|
|
9
9
|
import { parseInstallSpec } from '../src/install-spec.mjs'
|
|
@@ -21,6 +21,14 @@ test('good fixture passes manifest and version checks', () => {
|
|
|
21
21
|
assert.equal(result.checks[2].result, 'NA')
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
+
test('patch-only bundle reports C-1.2 as NA, not WARN', () => {
|
|
25
|
+
const result = runManifestChecks(path.join(here, '..', 'fixtures', 'bundle-patch-only'))
|
|
26
|
+
const dsc01 = result.checks.find((check) => check.id === 'DSC-01')
|
|
27
|
+
const entry = dsc01.details.find((detail) => detail.item === 'C-1.2')
|
|
28
|
+
assert.equal(entry.result, 'NA')
|
|
29
|
+
assert.match(entry.reason, /patch-only bundle/)
|
|
30
|
+
})
|
|
31
|
+
|
|
24
32
|
test('bad fixture fails version and warns licence', () => {
|
|
25
33
|
const result = runManifestChecks(bad)
|
|
26
34
|
assert.equal(result.checks[0].result, 'WARN')
|
|
@@ -170,3 +178,237 @@ test('entry: static claim recognizes without runtime', () => {
|
|
|
170
178
|
assert.equal(report.conclusion.level, 'DSH-ENTRY recognized')
|
|
171
179
|
assert.equal(report.conclusion.exitCode, 0)
|
|
172
180
|
})
|
|
181
|
+
|
|
182
|
+
test('DSC-10.4: flags a module-scope fs mutation in the entry module', () => {
|
|
183
|
+
const dir = path.join(here, '..', 'fixtures', 'import-side-effect')
|
|
184
|
+
const result = runManifestChecks(dir)
|
|
185
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
186
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
187
|
+
assert.ok(check.details.some((detail) => /top-level fs mutation/.test(detail.reason)), JSON.stringify(check.details))
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
test('DSC-10.4: ignores a module-scope fs mutation outside the entry module', () => {
|
|
191
|
+
const dir = path.join(here, '..', 'fixtures', 'import-side-effect-nonentry')
|
|
192
|
+
const result = runManifestChecks(dir)
|
|
193
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
194
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('DSC-10.4: a clean entry module still passes', () => {
|
|
198
|
+
const result = runManifestChecks(good)
|
|
199
|
+
const check = checkImportTimeAdvisory(readSources(good), result.entry?.relative)
|
|
200
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('DSC-10.1/2: the existing patterns are entry-scoped too', () => {
|
|
204
|
+
const dir = path.join(here, '..', 'fixtures', 'import-side-effect-nonentry')
|
|
205
|
+
const result = runManifestChecks(dir)
|
|
206
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
207
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('DSC-10.4: a read-only openSync is not a write mutation', () => {
|
|
211
|
+
const dir = path.join(here, '..', 'fixtures', 'import-open-readonly')
|
|
212
|
+
const result = runManifestChecks(dir)
|
|
213
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
214
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
test('DSC-10: no source files is NA, not WARN', () => {
|
|
218
|
+
const dir = path.join(here, '..', 'fixtures', 'no-source')
|
|
219
|
+
const check = checkImportTimeAdvisory(readSources(dir), 'index.mjs')
|
|
220
|
+
assert.equal(check.result, 'NA', check.reason)
|
|
221
|
+
assert.match(check.reason, /no source/)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
test('DSC-10.2: flags an immediate module-scope void main()', () => {
|
|
225
|
+
const dir = path.join(here, '..', 'fixtures', 'import-void-main')
|
|
226
|
+
const result = runManifestChecks(dir)
|
|
227
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
228
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
229
|
+
assert.ok(check.details.some((detail) => /immediate main/.test(detail.reason)), JSON.stringify(check.details))
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
test('DSC-10.1/2: AST catches top-level await, timer, process hooks and globals', () => {
|
|
233
|
+
const text = [
|
|
234
|
+
"await Promise.resolve()",
|
|
235
|
+
'for await (const item of []) {}',
|
|
236
|
+
"setInterval(() => {}, 1000)",
|
|
237
|
+
"process.on('SIGINT', () => {})",
|
|
238
|
+
"process.env.DSH_FIXTURE = '1'",
|
|
239
|
+
'globalThis.__dshFixture = true',
|
|
240
|
+
].join('\n')
|
|
241
|
+
const check = checkImportTimeAdvisory([{ relative: 'index.mjs', text }], 'index.mjs')
|
|
242
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
243
|
+
assert.equal(check.details.filter((detail) => /top-level await/.test(detail.reason)).length, 2)
|
|
244
|
+
for (const pattern of ['top-level setInterval', 'top-level process.on', 'top-level process.env assignment', 'top-level globalThis assignment']) {
|
|
245
|
+
assert.ok(check.details.some((detail) => detail.reason.includes(pattern)), `${pattern}: ${JSON.stringify(check.details)}`)
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
test('DSC-10.4: member fs writes and module-scope control flow count', () => {
|
|
250
|
+
const text = [
|
|
251
|
+
"import * as fs from 'node:fs'",
|
|
252
|
+
'if (process.env.DSH_FIXTURE) {',
|
|
253
|
+
" fs.writeFileSync('/tmp/dsh-fixture-member-write.txt', 'x')",
|
|
254
|
+
'}',
|
|
255
|
+
].join('\n')
|
|
256
|
+
const check = checkImportTimeAdvisory([{ relative: 'index.mjs', text }], 'index.mjs')
|
|
257
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
258
|
+
assert.ok(check.details.some((detail) => /top-level fs mutation/.test(detail.reason)), JSON.stringify(check.details))
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('DSC-10: function, arrow and class-method bodies are not module-scope side effects', () => {
|
|
262
|
+
const text = [
|
|
263
|
+
"function a() { writeFileSync('/tmp/a', 'x') }",
|
|
264
|
+
"const b = () => spawnSync('cmd')",
|
|
265
|
+
"class C { m() { process.on('x', () => {}) } }",
|
|
266
|
+
'const d = { n() { setInterval(() => {}, 1) } }',
|
|
267
|
+
].join('\n')
|
|
268
|
+
const check = checkImportTimeAdvisory([{ relative: 'index.mjs', text }], 'index.mjs')
|
|
269
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
test('DSC-12 C-12.4: ignores comment-only literals', () => {
|
|
273
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-comment')
|
|
274
|
+
const check = checkCredentials({}, readSources(dir))
|
|
275
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
test('DSC-12 C-12.4: ignores equality comparisons', () => {
|
|
279
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-compare')
|
|
280
|
+
const check = checkCredentials({}, readSources(dir))
|
|
281
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
test('DSC-12 C-12.4: still flags an actual set() grant', () => {
|
|
285
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-grant')
|
|
286
|
+
const check = checkCredentials({}, readSources(dir))
|
|
287
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
288
|
+
assert.ok(check.details.some((detail) => detail.item === 'C-12.4'), JSON.stringify(check.details))
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
test('DSC-12 C-12.4: console-only documentation string is not a grant', () => {
|
|
292
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-string')
|
|
293
|
+
const check = checkCredentials({}, readSources(dir))
|
|
294
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
295
|
+
assert.ok(!check.details.some((detail) => detail.item === 'C-12.4'), JSON.stringify(check.details))
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
test('DSC-12 C-12.4: console/desc documentation strings are not grants', () => {
|
|
299
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-doc-string')
|
|
300
|
+
const check = checkCredentials({}, readSources(dir))
|
|
301
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
302
|
+
assert.ok(!check.details.some((detail) => detail.item === 'C-12.4'), JSON.stringify(check.details))
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
test('DSC-11 C-11.4: console/desc documentation strings are not danger literals', () => {
|
|
306
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-doc-string')
|
|
307
|
+
const check = checkCapabilities({}, readSources(dir))
|
|
308
|
+
assert.ok(!check.details.some((detail) => detail.item === 'C-11.4'), JSON.stringify(check.details))
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
test('DSC-11 C-11.4: --add-dir alone is a C-12.4 concern, not C-11.4', () => {
|
|
312
|
+
const sources = [{ relative: 'index.mjs', text: "spawn('dsh', ['--add-dir', './docs'])\n" }]
|
|
313
|
+
const check = checkCapabilities({}, sources)
|
|
314
|
+
assert.ok(!check.details.some((detail) => detail.item === 'C-11.4'), JSON.stringify(check.details))
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
test('DSC-12 C-12.4: spawn args with --add-dir are a real command string', () => {
|
|
318
|
+
const dir = path.join(here, '..', 'fixtures', 'c12-command-arg')
|
|
319
|
+
const check = checkCredentials({}, readSources(dir))
|
|
320
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
321
|
+
assert.ok(check.details.some((detail) => detail.item === 'C-12.4'), JSON.stringify(check.details))
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
test('DSC-12 C-12.4: set/resolve/mode/switch contexts are real grants', () => {
|
|
325
|
+
const text = [
|
|
326
|
+
"svc.set(session, 'danger-full-access')",
|
|
327
|
+
"svc.resolve('danger-full-access')",
|
|
328
|
+
"const policy = { sandboxPolicy: { mode: 'danger-full-access' } }",
|
|
329
|
+
"switch (mode) { case 'danger-full-access': break }",
|
|
330
|
+
].join('\n')
|
|
331
|
+
const check = checkCredentials({}, [{ relative: 'index.mjs', text }])
|
|
332
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
333
|
+
const detail = check.details.find((item) => item.item === 'C-12.4')
|
|
334
|
+
assert.ok(detail, JSON.stringify(check.details))
|
|
335
|
+
assert.match(detail.reason, /\b4\b/)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
test('DSC-12 C-12.4: nested command properties outrank documentation keys', () => {
|
|
339
|
+
const check = checkCredentials({}, [{ relative: 'index.mjs', text: "const policy = { sandboxPolicy: { description: 'danger-full-access' } }\n" }])
|
|
340
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
test('DSC-12 C-12.4: an unknown context stays a conservative warning', () => {
|
|
344
|
+
const check = checkCredentials({}, [{ relative: 'index.mjs', text: "const mode = 'danger-full-access'\n" }])
|
|
345
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
test('DSC-12 C-12.4: an unparsable source is not-run, not PASS', () => {
|
|
349
|
+
const check = checkCredentials({}, [{ relative: 'index.mjs', text: 'const broken = {\n' }])
|
|
350
|
+
assert.equal(check.result, 'ERROR', check.reason)
|
|
351
|
+
assert.equal(check.coverage, 'not-run')
|
|
352
|
+
assert.ok(check.details.some((detail) => detail.item === 'C-12.4' && /not-run/.test(detail.reason)), JSON.stringify(check.details))
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
test('DSC-10.3: follows a local relative import and flags its top-level fs mutation', () => {
|
|
356
|
+
const dir = path.join(here, '..', 'fixtures', 'import-local-side-effect')
|
|
357
|
+
const result = runManifestChecks(dir)
|
|
358
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
359
|
+
assert.equal(check.result, 'WARN', check.reason)
|
|
360
|
+
assert.ok(check.details.some((detail) => /top-level fs mutation/.test(detail.reason) && /side-effectful\.mjs/.test(detail.reason)), JSON.stringify(check.details))
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
test('DSC-10.3: a package-only entry is PASS with a C-10.3 not-run coverage note', () => {
|
|
364
|
+
const dir = path.join(here, '..', 'fixtures', 'import-package-only')
|
|
365
|
+
const result = runManifestChecks(dir)
|
|
366
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
367
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
368
|
+
const note = check.details.find((detail) => detail.item === 'C-10.3')
|
|
369
|
+
assert.ok(note, JSON.stringify(check.details))
|
|
370
|
+
assert.match(note.reason, /not-run/)
|
|
371
|
+
assert.match(note.reason, /node:path/)
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
test('DSC-10.3: an unresolved local import records not-run without becoming a WARN', () => {
|
|
375
|
+
const sources = [{ relative: 'index.mjs', text: "import './missing-module.mjs'\n" }]
|
|
376
|
+
const check = checkImportTimeAdvisory(sources, 'index.mjs')
|
|
377
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
378
|
+
assert.ok(check.details.some((detail) => detail.item === 'C-10.3' && /not-run/.test(detail.reason)), JSON.stringify(check.details))
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
test('DSC-10.3: a require inside a function is not an import-time edge', () => {
|
|
382
|
+
const sources = [
|
|
383
|
+
{ relative: 'index.mjs', text: "function load() { return require('./side-effectful.mjs') }\n" },
|
|
384
|
+
{ relative: 'side-effectful.mjs', text: "writeFileSync('/tmp/x', 'x')\n" },
|
|
385
|
+
]
|
|
386
|
+
const check = checkImportTimeAdvisory(sources, 'index.mjs')
|
|
387
|
+
assert.equal(check.result, 'PASS', check.reason)
|
|
388
|
+
assert.ok(!check.details.some((detail) => /side-effectful/.test(detail.reason)), JSON.stringify(check.details))
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
test('DSC-10: an unparsable entry is ERROR/not-run, not PASS', () => {
|
|
392
|
+
const dir = path.join(here, '..', 'fixtures', 'import-parse-error')
|
|
393
|
+
const result = runManifestChecks(dir)
|
|
394
|
+
const check = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
395
|
+
assert.equal(check.result, 'ERROR', check.reason)
|
|
396
|
+
assert.equal(check.coverage, 'not-run')
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
test('DSC-10/DSC-12: a broken .d.ts is skipped, not ERROR', () => {
|
|
400
|
+
const dir = path.join(here, '..', 'fixtures', 'declaration-file')
|
|
401
|
+
const result = runManifestChecks(dir)
|
|
402
|
+
const c10 = checkImportTimeAdvisory(readSources(dir), result.entry?.relative)
|
|
403
|
+
const c12 = checkCredentials({}, readSources(dir))
|
|
404
|
+
assert.equal(c10.result, 'PASS', c10.reason)
|
|
405
|
+
assert.equal(c12.result, 'PASS', c12.reason)
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
test('DSC-12 C-12.4: one unparsable non-entry file is partial, not ERROR', () => {
|
|
409
|
+
const dir = path.join(here, '..', 'fixtures', 'parse-error-nonentry')
|
|
410
|
+
const check = checkCredentials({}, readSources(dir))
|
|
411
|
+
assert.notEqual(check.result, 'ERROR', check.reason)
|
|
412
|
+
assert.equal(check.coverage, 'partial')
|
|
413
|
+
assert.ok(check.details.some((detail) => detail.item === 'C-12.4' && /not-run/.test(detail.reason)), JSON.stringify(check.details))
|
|
414
|
+
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Vendored @babel/parser
|
|
2
|
+
|
|
3
|
+
- Package: `@babel/parser` 8.1.0 (MIT), with `@babel/types`,
|
|
4
|
+
`@babel/helper-string-parser`, `@babel/helper-validator-identifier`.
|
|
5
|
+
- Why: the checker needs a real AST for TypeScript/JSX as well as JS. acorn
|
|
6
|
+
alone cannot parse `.ts`/`.tsx`; Babel can.
|
|
7
|
+
- Layout: `node_modules/@babel/*` so `@babel/parser` resolves its own deps
|
|
8
|
+
without network access. `index.cjs` is the only entry the checker imports.
|
|
9
|
+
- Licenses: `node_modules/@babel/parser/LICENSE` and the sibling packages.
|
|
10
|
+
- Update: copy the four packages from a fresh `npm install @babel/parser@8.1.0`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @babel/helper-string-parser
|
|
2
|
+
|
|
3
|
+
> A utility package to parse strings
|
|
4
|
+
|
|
5
|
+
See our website [@babel/helper-string-parser](https://babeljs.io/docs/babel-helper-string-parser) for more information.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Using npm:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install --save @babel/helper-string-parser
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
or using yarn:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
yarn add @babel/helper-string-parser
|
|
19
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
type StringContentsErrorHandlers = EscapedCharErrorHandlers & {
|
|
2
|
+
unterminated(initialPos: number, initialLineStart: number, initialCurLine: number): void;
|
|
3
|
+
};
|
|
4
|
+
declare function readStringContents(type: "single" | "double" | "template", input: string, pos: number, lineStart: number, curLine: number, errors: StringContentsErrorHandlers): {
|
|
5
|
+
pos: number;
|
|
6
|
+
str: string;
|
|
7
|
+
firstInvalidLoc: {
|
|
8
|
+
pos: number;
|
|
9
|
+
lineStart: number;
|
|
10
|
+
curLine: number;
|
|
11
|
+
} | null;
|
|
12
|
+
lineStart: number;
|
|
13
|
+
curLine: number;
|
|
14
|
+
};
|
|
15
|
+
type EscapedCharErrorHandlers = HexCharErrorHandlers & CodePointErrorHandlers & {
|
|
16
|
+
strictNumericEscape(pos: number, lineStart: number, curLine: number): void;
|
|
17
|
+
};
|
|
18
|
+
type HexCharErrorHandlers = IntErrorHandlers & {
|
|
19
|
+
invalidEscapeSequence(pos: number, lineStart: number, curLine: number): void;
|
|
20
|
+
};
|
|
21
|
+
type IntErrorHandlers = {
|
|
22
|
+
numericSeparatorInEscapeSequence(pos: number, lineStart: number, curLine: number): void;
|
|
23
|
+
unexpectedNumericSeparator(pos: number, lineStart: number, curLine: number): void;
|
|
24
|
+
invalidDigit(pos: number, lineStart: number, curLine: number, radix: number): void;
|
|
25
|
+
};
|
|
26
|
+
declare function readInt(input: string, pos: number, lineStart: number, curLine: number, radix: number, len: number | undefined, forceLen: boolean, allowNumSeparator: boolean | "bail", errors: IntErrorHandlers, bailOnError: boolean): {
|
|
27
|
+
n: null;
|
|
28
|
+
pos: number;
|
|
29
|
+
} | {
|
|
30
|
+
n: number;
|
|
31
|
+
pos: number;
|
|
32
|
+
};
|
|
33
|
+
type CodePointErrorHandlers = HexCharErrorHandlers & {
|
|
34
|
+
invalidCodePoint(pos: number, lineStart: number, curLine: number): void;
|
|
35
|
+
};
|
|
36
|
+
declare function readCodePoint(input: string, pos: number, lineStart: number, curLine: number, throwOnInvalid: boolean, errors: CodePointErrorHandlers): {
|
|
37
|
+
code: number | null;
|
|
38
|
+
pos: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { type CodePointErrorHandlers, type IntErrorHandlers, type StringContentsErrorHandlers, readCodePoint, readInt, readStringContents };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
var _isDigit = function isDigit(code) {
|
|
2
|
+
return code >= 48 && code <= 57;
|
|
3
|
+
};
|
|
4
|
+
const forbiddenNumericSeparatorSiblings = {
|
|
5
|
+
decBinOct: new Set([46, 66, 69, 79, 95, 98, 101, 111, 43, 45]),
|
|
6
|
+
hex: new Set([46, 88, 95, 120])
|
|
7
|
+
};
|
|
8
|
+
const isAllowedNumericSeparatorSibling = {
|
|
9
|
+
bin: ch => ch === 48 || ch === 49,
|
|
10
|
+
oct: ch => ch >= 48 && ch <= 55,
|
|
11
|
+
dec: ch => ch >= 48 && ch <= 57,
|
|
12
|
+
hex: ch => ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102
|
|
13
|
+
};
|
|
14
|
+
function readStringContents(type, input, pos, lineStart, curLine, errors) {
|
|
15
|
+
const initialPos = pos;
|
|
16
|
+
const initialLineStart = lineStart;
|
|
17
|
+
const initialCurLine = curLine;
|
|
18
|
+
let out = "";
|
|
19
|
+
let firstInvalidLoc = null;
|
|
20
|
+
let chunkStart = pos;
|
|
21
|
+
const {
|
|
22
|
+
length
|
|
23
|
+
} = input;
|
|
24
|
+
for (;;) {
|
|
25
|
+
if (pos >= length) {
|
|
26
|
+
errors.unterminated(initialPos, initialLineStart, initialCurLine);
|
|
27
|
+
out += input.slice(chunkStart, pos);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
const ch = input.charCodeAt(pos);
|
|
31
|
+
if (isStringEnd(type, ch, input, pos)) {
|
|
32
|
+
out += input.slice(chunkStart, pos);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (ch === 92) {
|
|
36
|
+
out += input.slice(chunkStart, pos);
|
|
37
|
+
const res = readEscapedChar(input, pos, lineStart, curLine, type === "template", errors);
|
|
38
|
+
if (res.ch === null && !firstInvalidLoc) {
|
|
39
|
+
firstInvalidLoc = {
|
|
40
|
+
pos,
|
|
41
|
+
lineStart,
|
|
42
|
+
curLine
|
|
43
|
+
};
|
|
44
|
+
} else {
|
|
45
|
+
out += res.ch;
|
|
46
|
+
}
|
|
47
|
+
({
|
|
48
|
+
pos,
|
|
49
|
+
lineStart,
|
|
50
|
+
curLine
|
|
51
|
+
} = res);
|
|
52
|
+
chunkStart = pos;
|
|
53
|
+
} else if (ch === 8232 || ch === 8233) {
|
|
54
|
+
++pos;
|
|
55
|
+
++curLine;
|
|
56
|
+
lineStart = pos;
|
|
57
|
+
} else if (ch === 10 || ch === 13) {
|
|
58
|
+
if (type === "template") {
|
|
59
|
+
out += input.slice(chunkStart, pos) + "\n";
|
|
60
|
+
++pos;
|
|
61
|
+
if (ch === 13 && input.charCodeAt(pos) === 10) {
|
|
62
|
+
++pos;
|
|
63
|
+
}
|
|
64
|
+
++curLine;
|
|
65
|
+
chunkStart = lineStart = pos;
|
|
66
|
+
} else {
|
|
67
|
+
errors.unterminated(initialPos, initialLineStart, initialCurLine);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
++pos;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
pos,
|
|
75
|
+
str: out,
|
|
76
|
+
firstInvalidLoc,
|
|
77
|
+
lineStart,
|
|
78
|
+
curLine
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function isStringEnd(type, ch, input, pos) {
|
|
82
|
+
if (type === "template") {
|
|
83
|
+
return ch === 96 || ch === 36 && input.charCodeAt(pos + 1) === 123;
|
|
84
|
+
}
|
|
85
|
+
return ch === (type === "double" ? 34 : 39);
|
|
86
|
+
}
|
|
87
|
+
function readEscapedChar(input, pos, lineStart, curLine, inTemplate, errors) {
|
|
88
|
+
const throwOnInvalid = !inTemplate;
|
|
89
|
+
pos++;
|
|
90
|
+
const res = ch => ({
|
|
91
|
+
pos,
|
|
92
|
+
ch,
|
|
93
|
+
lineStart,
|
|
94
|
+
curLine
|
|
95
|
+
});
|
|
96
|
+
const ch = input.charCodeAt(pos++);
|
|
97
|
+
switch (ch) {
|
|
98
|
+
case 110:
|
|
99
|
+
return res("\n");
|
|
100
|
+
case 114:
|
|
101
|
+
return res("\r");
|
|
102
|
+
case 120:
|
|
103
|
+
{
|
|
104
|
+
let code;
|
|
105
|
+
({
|
|
106
|
+
code,
|
|
107
|
+
pos
|
|
108
|
+
} = readHexChar(input, pos, lineStart, curLine, 2, false, throwOnInvalid, errors));
|
|
109
|
+
return res(code === null ? null : String.fromCharCode(code));
|
|
110
|
+
}
|
|
111
|
+
case 117:
|
|
112
|
+
{
|
|
113
|
+
let code;
|
|
114
|
+
({
|
|
115
|
+
code,
|
|
116
|
+
pos
|
|
117
|
+
} = readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors));
|
|
118
|
+
return res(code === null ? null : String.fromCodePoint(code));
|
|
119
|
+
}
|
|
120
|
+
case 116:
|
|
121
|
+
return res("\t");
|
|
122
|
+
case 98:
|
|
123
|
+
return res("\b");
|
|
124
|
+
case 118:
|
|
125
|
+
return res("\u000b");
|
|
126
|
+
case 102:
|
|
127
|
+
return res("\f");
|
|
128
|
+
case 13:
|
|
129
|
+
if (input.charCodeAt(pos) === 10) {
|
|
130
|
+
++pos;
|
|
131
|
+
}
|
|
132
|
+
case 10:
|
|
133
|
+
lineStart = pos;
|
|
134
|
+
++curLine;
|
|
135
|
+
case 8232:
|
|
136
|
+
case 8233:
|
|
137
|
+
return res("");
|
|
138
|
+
case 56:
|
|
139
|
+
case 57:
|
|
140
|
+
if (inTemplate) {
|
|
141
|
+
return res(null);
|
|
142
|
+
} else {
|
|
143
|
+
errors.strictNumericEscape(pos - 1, lineStart, curLine);
|
|
144
|
+
}
|
|
145
|
+
default:
|
|
146
|
+
if (ch >= 48 && ch <= 55) {
|
|
147
|
+
const startPos = pos - 1;
|
|
148
|
+
const match = /^[0-7]+/.exec(input.slice(startPos, pos + 2));
|
|
149
|
+
let octalStr = match[0];
|
|
150
|
+
let octal = parseInt(octalStr, 8);
|
|
151
|
+
if (octal > 255) {
|
|
152
|
+
octalStr = octalStr.slice(0, -1);
|
|
153
|
+
octal = parseInt(octalStr, 8);
|
|
154
|
+
}
|
|
155
|
+
pos += octalStr.length - 1;
|
|
156
|
+
const next = input.charCodeAt(pos);
|
|
157
|
+
if (octalStr !== "0" || next === 56 || next === 57) {
|
|
158
|
+
if (inTemplate) {
|
|
159
|
+
return res(null);
|
|
160
|
+
} else {
|
|
161
|
+
errors.strictNumericEscape(startPos, lineStart, curLine);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return res(String.fromCharCode(octal));
|
|
165
|
+
}
|
|
166
|
+
return res(String.fromCharCode(ch));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function readHexChar(input, pos, lineStart, curLine, len, forceLen, throwOnInvalid, errors) {
|
|
170
|
+
const initialPos = pos;
|
|
171
|
+
let n;
|
|
172
|
+
({
|
|
173
|
+
n,
|
|
174
|
+
pos
|
|
175
|
+
} = readInt(input, pos, lineStart, curLine, 16, len, forceLen, false, errors, !throwOnInvalid));
|
|
176
|
+
if (n === null) {
|
|
177
|
+
if (throwOnInvalid) {
|
|
178
|
+
errors.invalidEscapeSequence(initialPos, lineStart, curLine);
|
|
179
|
+
} else {
|
|
180
|
+
pos = initialPos - 1;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
code: n,
|
|
185
|
+
pos
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function readInt(input, pos, lineStart, curLine, radix, len, forceLen, allowNumSeparator, errors, bailOnError) {
|
|
189
|
+
const start = pos;
|
|
190
|
+
const forbiddenSiblings = radix === 16 ? forbiddenNumericSeparatorSiblings.hex : forbiddenNumericSeparatorSiblings.decBinOct;
|
|
191
|
+
const isAllowedSibling = radix === 16 ? isAllowedNumericSeparatorSibling.hex : radix === 10 ? isAllowedNumericSeparatorSibling.dec : radix === 8 ? isAllowedNumericSeparatorSibling.oct : isAllowedNumericSeparatorSibling.bin;
|
|
192
|
+
let invalid = false;
|
|
193
|
+
let total = 0;
|
|
194
|
+
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
|
|
195
|
+
const code = input.charCodeAt(pos);
|
|
196
|
+
let val;
|
|
197
|
+
if (code === 95 && allowNumSeparator !== "bail") {
|
|
198
|
+
const prev = input.charCodeAt(pos - 1);
|
|
199
|
+
const next = input.charCodeAt(pos + 1);
|
|
200
|
+
if (!allowNumSeparator) {
|
|
201
|
+
if (bailOnError) return {
|
|
202
|
+
n: null,
|
|
203
|
+
pos
|
|
204
|
+
};
|
|
205
|
+
errors.numericSeparatorInEscapeSequence(pos, lineStart, curLine);
|
|
206
|
+
} else if (Number.isNaN(next) || !isAllowedSibling(next) || forbiddenSiblings.has(prev)) {
|
|
207
|
+
if (bailOnError) return {
|
|
208
|
+
n: null,
|
|
209
|
+
pos
|
|
210
|
+
};
|
|
211
|
+
errors.unexpectedNumericSeparator(pos, lineStart, curLine);
|
|
212
|
+
}
|
|
213
|
+
++pos;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (code >= 97) {
|
|
217
|
+
val = code - 97 + 10;
|
|
218
|
+
} else if (code >= 65) {
|
|
219
|
+
val = code - 65 + 10;
|
|
220
|
+
} else if (_isDigit(code)) {
|
|
221
|
+
val = code - 48;
|
|
222
|
+
} else {
|
|
223
|
+
val = Infinity;
|
|
224
|
+
}
|
|
225
|
+
if (val >= radix) {
|
|
226
|
+
if (val <= 9) {
|
|
227
|
+
if (bailOnError) return {
|
|
228
|
+
n: null,
|
|
229
|
+
pos
|
|
230
|
+
};
|
|
231
|
+
errors.invalidDigit(pos, lineStart, curLine, radix);
|
|
232
|
+
val = 0;
|
|
233
|
+
} else if (forceLen) {
|
|
234
|
+
val = 0;
|
|
235
|
+
invalid = true;
|
|
236
|
+
} else {
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
++pos;
|
|
241
|
+
total = total * radix + val;
|
|
242
|
+
}
|
|
243
|
+
if (pos === start || len != null && pos - start !== len || invalid) {
|
|
244
|
+
return {
|
|
245
|
+
n: null,
|
|
246
|
+
pos
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
n: total,
|
|
251
|
+
pos
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function readCodePoint(input, pos, lineStart, curLine, throwOnInvalid, errors) {
|
|
255
|
+
const ch = input.charCodeAt(pos);
|
|
256
|
+
let code;
|
|
257
|
+
if (ch === 123) {
|
|
258
|
+
++pos;
|
|
259
|
+
({
|
|
260
|
+
code,
|
|
261
|
+
pos
|
|
262
|
+
} = readHexChar(input, pos, lineStart, curLine, input.indexOf("}", pos) - pos, true, throwOnInvalid, errors));
|
|
263
|
+
++pos;
|
|
264
|
+
if (code !== null && code > 0x10ffff) {
|
|
265
|
+
if (throwOnInvalid) {
|
|
266
|
+
errors.invalidCodePoint(pos, lineStart, curLine);
|
|
267
|
+
} else {
|
|
268
|
+
return {
|
|
269
|
+
code: null,
|
|
270
|
+
pos
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
({
|
|
276
|
+
code,
|
|
277
|
+
pos
|
|
278
|
+
} = readHexChar(input, pos, lineStart, curLine, 4, false, throwOnInvalid, errors));
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
code,
|
|
282
|
+
pos
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export { readCodePoint, readInt, readStringContents };
|